package cn.jingzhuan.fm.ui.widget

import android.animation.Animator
import android.animation.ValueAnimator
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import cn.jingzhuan.fm.R
import cn.jingzhuan.fm.utils.DisplayUtils

class JZProgressBar : View {

    var jzProgressBarTextGenerator: JZProgressBarTextGenerator? = null
    /*rect_progress member*/
    private lateinit var mBgRect: RectF
    private lateinit var mProgressRect: RectF
    /*common member*/
    private var mWidth: Int = 0
    private var mHeight: Int = 0
    private var mType: Int = 0
    private var mProgressColor: Int = 0
    private var mBackgroundColor: Int = 0
    private var isAnimating = false
    var maxValue: Int = 0
    private var mValue: Int = 0
    private var mAnimator: ValueAnimator? = null
    private var backgroundVisible: Boolean = true
    private val mBackgroundPaint = Paint()
    private val mPaint = Paint()
    private val mTextPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    private val mArcOval = RectF()
    private var mText: String? = ""
    private var mStrokeWidth: Int = 0
    private var mCircleRadius: Int = 0
    private var mCenterPoint: Point? = null

    var progress: Int
        get() = mValue
        set(progress) {
            if (progress > mValue && progress < 0) {
                return
            }
            if (isAnimating) {
                isAnimating = false
                mAnimator!!.cancel()
            }
            val oldValue = mValue
            mValue = progress
            startAnimation(oldValue, progress)
        }


    constructor(context: Context) : super(context) {
        setup(context, null)
    }

    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {
        setup(context, attrs)
    }

    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        setup(context, attrs)
    }

    fun setup(context: Context, attrs: AttributeSet?) {
        val array = context.obtainStyledAttributes(attrs, R.styleable.ProgressBar)
        mType = array.getInt(R.styleable.ProgressBar_type, TYPE_RECT)
        mProgressColor = array.getColor(R.styleable.ProgressBar_progress_color, DEFAULT_PROGRESS_COLOR)
        mBackgroundColor = array.getColor(R.styleable.ProgressBar_background_color, DEFAULT_BACKGROUND_COLOR)

        maxValue = array.getInt(R.styleable.ProgressBar_max_value, 100)
        mValue = array.getInt(R.styleable.ProgressBar_value, 0)

        val isRoundCap = array.getBoolean(R.styleable.ProgressBar_stroke_round_cap, false)

        backgroundVisible = array.getBoolean(R.styleable.ProgressBar_background_visible, true)

        var textSize = DEFAULT_TEXT_SIZE
        if (array.hasValue(R.styleable.ProgressBar_android_textSize)) {
            textSize = array.getDimensionPixelSize(R.styleable.ProgressBar_android_textSize, DEFAULT_TEXT_SIZE)
        }
        var textColor = DEFAULT_TEXT_COLOR
        if (array.hasValue(R.styleable.ProgressBar_android_textColor)) {
            textColor = array.getColor(R.styleable.ProgressBar_android_textColor, DEFAULT_TEXT_COLOR)
        }

        if (mType == TYPE_CIRCLE) {
            mStrokeWidth = array.getDimensionPixelSize(R.styleable.ProgressBar_stroke_width, DisplayUtils.dip2px(context,40f))
        }
        array.recycle()
        configPaint(textColor, textSize, isRoundCap)

        progress = mValue
    }

    private fun configShape() {
        if (mType == TYPE_RECT) {
            mBgRect = RectF(paddingLeft.toFloat(), paddingTop.toFloat(), (mWidth + paddingLeft).toFloat(), (mHeight + paddingTop).toFloat())
            mProgressRect = RectF()
        } else {
            mCircleRadius = (Math.min(mWidth, mHeight) - mStrokeWidth) / 2
            mCenterPoint = Point(mWidth / 2, mHeight / 2)
        }
    }

    private fun configPaint(textColor: Int, textSize: Int, isRoundCap: Boolean) {
        mPaint.color = mProgressColor
        mBackgroundPaint.color = mBackgroundColor
        if (mType == TYPE_RECT) {
            mPaint.style = Paint.Style.FILL
            mBackgroundPaint.style = Paint.Style.FILL
        } else {
            mPaint.style = Paint.Style.STROKE
            mPaint.strokeWidth = mStrokeWidth.toFloat()
            mPaint.isAntiAlias = true
            if (isRoundCap) {
                mPaint.strokeCap = Paint.Cap.ROUND
            }
            mBackgroundPaint.style = Paint.Style.STROKE
            mBackgroundPaint.strokeWidth = mStrokeWidth.toFloat()
            mBackgroundPaint.isAntiAlias = true
        }
        mTextPaint.color = textColor
        mTextPaint.textSize = textSize.toFloat()
        mTextPaint.textAlign = Paint.Align.CENTER
    }

    /**
     * 设置进度文案的文字大小
     *
     * @see .setTextColor
     * @see .setQMUIProgressBarTextGenerator
     */
    fun setTextSize(textSize: Int) {
        mTextPaint.textSize = textSize.toFloat()
        invalidate()
    }

    /**
     * 设置进度文案的文字颜色
     *
     * @see .setTextSize
     * @see .setQMUIProgressBarTextGenerator
     */
    fun setTextColor(textColor: Int) {
        mTextPaint.color = textColor
        invalidate()
    }

    /**
     * 设置环形进度条的两端是否有圆形的线帽，类型为[.TYPE_CIRCLE]时生效
     */
    fun setStrokeRoundCap(isRoundCap: Boolean) {
        mPaint.strokeCap = if (isRoundCap) Paint.Cap.ROUND else Paint.Cap.BUTT
        invalidate()
    }

    override fun onDraw(canvas: Canvas) {
        if (jzProgressBarTextGenerator != null) {
            mText = jzProgressBarTextGenerator!!.generateText(this, mValue, maxValue)
        }
        if (mType == TYPE_RECT) {
            drawRect(canvas)
        } else {
            drawCircle(canvas)
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        mWidth = measuredWidth - paddingLeft - paddingRight
        mHeight = measuredHeight - paddingTop - paddingBottom

        configShape()
        setMeasuredDimension(mWidth, mHeight)
    }

    private fun drawRect(canvas: Canvas) {
        if(backgroundVisible) {
            canvas.drawRect(mBgRect, mBackgroundPaint)
        }
        mProgressRect.set(paddingLeft.toFloat(), paddingTop.toFloat(), (paddingLeft + parseValueToWidth()).toFloat(), (paddingTop + mHeight).toFloat())
        canvas.drawRect(mProgressRect, mPaint)
        if (mText != null && mText!!.length > 0) {
            val fontMetrics = mTextPaint.fontMetricsInt
            val baseline = mBgRect.top + (mBgRect.height() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top
            canvas.drawText(mText!!, mBgRect.centerX(), baseline, mTextPaint)
        }
    }

    private fun drawCircle(canvas: Canvas) {
        if(backgroundVisible) {
            canvas.drawCircle(mCenterPoint!!.x.toFloat(), mCenterPoint!!.y.toFloat(), mCircleRadius.toFloat(), mBackgroundPaint)
        }
        mArcOval.left = (mCenterPoint!!.x - mCircleRadius).toFloat()
        mArcOval.right = (mCenterPoint!!.x + mCircleRadius).toFloat()
        mArcOval.top = (mCenterPoint!!.y - mCircleRadius).toFloat()
        mArcOval.bottom = (mCenterPoint!!.y + mCircleRadius).toFloat()
        canvas.drawArc(mArcOval, 270f, (360 * mValue / maxValue).toFloat(), false, mPaint)
        if (mText != null && mText!!.length > 0) {
            val fontMetrics = mTextPaint.fontMetricsInt
            val baseline = mArcOval.top + (mArcOval.height() - fontMetrics.bottom + fontMetrics.top) / 2 - fontMetrics.top
            canvas.drawText(mText!!, mCenterPoint!!.x.toFloat(), baseline, mTextPaint)
        }
    }

    private fun parseValueToWidth(): Int {
        return mWidth * mValue / maxValue
    }

    private fun startAnimation(start: Int, end: Int) {
        mAnimator = ValueAnimator.ofInt(start, end)
        val duration = Math.abs(TOTAL_DURATION * (end - start) / maxValue)
        mAnimator!!.duration = duration.toLong()
        mAnimator!!.addUpdateListener { animation ->
            mValue = animation.animatedValue as Int
            invalidate()
        }

        mAnimator!!.addListener(object : Animator.AnimatorListener {
            override fun onAnimationStart(animation: Animator) {
                isAnimating = true
            }

            override fun onAnimationEnd(animation: Animator) {
                isAnimating = false
            }

            override fun onAnimationCancel(animation: Animator) {}

            override fun onAnimationRepeat(animation: Animator) {}
        })
        mAnimator!!.start()
    }

    interface JZProgressBarTextGenerator {
        /**
         * 设置进度文案, [JZProgressBar] 会在进度更新时调用该方法获取要显示的文案
         * @param value 当前进度值
         * @param maxValue 最大进度值
         * @return 进度文案
         */
        fun generateText(progressBar: JZProgressBar, value: Int, maxValue: Int): String
    }

    companion object {

        var TYPE_RECT = 0
        var TYPE_CIRCLE = 1
        var TOTAL_DURATION = 1000
        var DEFAULT_PROGRESS_COLOR = Color.BLUE
        var DEFAULT_BACKGROUND_COLOR = Color.GRAY
        var DEFAULT_TEXT_SIZE = 20
        var DEFAULT_TEXT_COLOR = Color.BLACK
    }
}